﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;

namespace BizElements.TemplateEngine
{
    /// <summary>Caches temporary assemblies in memory and optionally in temp directory.</summary>
    internal static class TemplateExpressionAssemblyCache
    {
        #region RAM cache.

        static readonly Dictionary<string, Assembly> CompiledSourceCache = new Dictionary<string, Assembly>();

        public static Assembly GetAssembly(string source)
        {
            Assembly asm;
            CompiledSourceCache.TryGetValue(source, out asm);
            // Permanent cache not required - performance is good without it.
            //if (asm == null)
            //    asm = LoadAssemblyFromTempFolder(source);

            return asm;
        }

        public static void SetAssembly(string source, Assembly asm)
        {
            bool isAlreadyCached = CompiledSourceCache.ContainsKey(source);
            if (!isAlreadyCached)
            {
                CompiledSourceCache[source] = asm;
                // Permanent cache not required - performance is good without it.
                //SaveAssemblyToTempFolder(source, asm);
            }
        }

        #endregion

        #region File management - commented - not used.

        //private static Assembly LoadAssemblyFromTempFolder(string source)
        //{
        //    string filePath = GetTempAssemblyFilePath(source);
        //    if (File.Exists(filePath))
        //        return Assembly.LoadFile(filePath);
        //    else
        //        return null;
        //}

        //private static void SaveAssemblyToTempFolder(string source, Assembly asm)
        //{
        //    EnsureTempAssemblyFolderExists();
        //    string filePath = GetTempAssemblyFilePath(source);
        //    File.Copy(asm.Location, filePath, true);
        //}

        //private static string GetTempAssemblyFolder()
        //{
        //    return Directory.GetCurrentDirectory() + @"\TemplateExpressionAssemblyCache";
        //}

        //private static void EnsureTempAssemblyFolderExists()
        //{
        //    string tempDir = GetTempAssemblyFolder();
        //    if (!Directory.Exists(tempDir))
        //        Directory.CreateDirectory(tempDir);
        //}

        //private static byte[] MD5Key = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

        //private static string ComputeBase64Hash(string source)
        //{
        //    UTF8Encoding utf8 = new UTF8Encoding();
        //    byte[] sourceBinary = utf8.GetBytes(source);
        //    var hashAlgorithm = new HMACMD5(MD5Key);
        //    byte[] hashBinary = hashAlgorithm.ComputeHash(sourceBinary);
        //    string b64hash = Convert.ToBase64String(hashBinary);
        //    StringBuilder onlyDigitsAndLetters = new StringBuilder();
        //    foreach (char c in b64hash)
        //    {
        //        if (char.IsLetterOrDigit(c))
        //            onlyDigitsAndLetters.Append(c);
        //    }

        //    return onlyDigitsAndLetters.ToString();
        //}

        //private static string GetTempAssemblyFileName(string source)
        //{
        //    string name = ComputeBase64Hash(source) + ".dll";
        //    return name;
        //}

        //private static string GetTempAssemblyFilePath(string source)
        //{
        //    return GetTempAssemblyFolder() + @"\" + GetTempAssemblyFileName(source);
        //}

        //private static void CopyStream(Stream inStream, FileStream outStream)
        //{
        //    const int BufferSize = 4096;
        //    byte[] bytes = new byte[BufferSize];
        //    int bytesReadCount;
        //    while ((bytesReadCount = inStream.Read(bytes, 0, BufferSize)) > 0)
        //    {
        //        outStream.Write(bytes, 0, bytesReadCount);
        //    }
        //}

        #endregion
    }
}
